﻿
//	------------------------------------------------------------------------------
//                                       _                          
//              _ __ ___   ___ _ __ ___ | |__  _ __ __ _ _ __   ___ 
//             | '_ ` _ \ / _ \ '_ ` _ \| '_ \| '__/ _` | '_ \ / _ \
//             | | | | | |  __/ | | | | | |_) | | | (_| | | | |  __/
//             |_| |_| |_|\___|_| |_| |_|_.__/|_|  \__,_|_| |_|\___|
//                                                     
//	------------------------------------------------------------------------------

#region - License -
//
//	------------------------------------------------------------------------------                                                   
//	         Copyright (c) 2010 Peter Vyvey (peter.vyvey@chiliware.be)
//	------------------------------------------------------------------------------
//
//
//	This file is part of CHILIWARE MEMBRANE.
//
//	CHILIWARE MEMBRANE is free software: you can redistribute it and/or modify
//	it under the terms of the GNU Lesser General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	CHILIWARE MEMBRANE is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public License
//	along with CHILIWARE MEMBRANE.  If not, see <http://www.gnu.org/licenses/>.
//
//
#endregion

#region - Changes -

//	peter.vyvey@chiliware.be     2010-08-09      Created.

#endregion

#region - Using -

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;

#endregion

namespace Chiliware.Membrane.Extension
{
	#region - EnumExtension -

	/// <summary>
	/// Extends functionality on enumerations.
	/// </summary>
	public static class EnumExtension
	{
		#region - Public static methods -

		/// <summary>
		/// Converts a string to a member of a given enumeration of type T.
		/// </summary>
		/// <typeparam name="T">A enumeration type.</typeparam>
		/// <param name="value">The string value.</param>
		/// <returns>Enumeration value defined by type T.</returns>
		/// <exception cref="System.ArgumentException">Thrown if the type parameter T is not an enumeration.</exception>
		public static T ToEnum<T>(this string value)
		{
			value.CatchNullOrEmptyArgument("value");

			Type enumerationType = typeof(T);

			// This method is only allowed with enumerations.
			if (!enumerationType.IsEnum)
			{
				throw new ArgumentException("The type parameter T must be an enumeration.");
			}

			return (T)Enum.Parse(typeof(T), value, true);
		}

		/// <summary>
		/// Tries to convert a string to a member of a given enumeration of type T.
		/// </summary>
		/// <typeparam name="T">A enumeration type.</typeparam>
		/// <param name="value">The string value.</param>
		/// <param name="enumeration">The enumeration parameter that will hold the parsed result.</param>
		/// <returns>A boolean indicating if the string value is converted to a value of the enumeration.</returns>
		public static bool TryGetEnum<T>(this string value, out T enumeration)
		{
			bool result = false;

			// Get the enumeration values into an list, 
			// so the application flow is not determined by a possible exception while trying to parse the string value
			IEnumerable<string> items = null;
#if (SILVERLIGHT)
			items = EnumExtension.GetValues<T>().ToList<object>().Select(o => o.ToString());
#else
			items = Enum.GetValues(typeof(T)).ToList<object>().Select(o => o.ToString());
#endif

			// If the value is in the list then convert the value to the enumeration member
			if (items.Contains(value))
			{
				enumeration = value.ToEnum<T>();
				result = true;
			}
			else
			{
				enumeration = default(T);
			}

			return result;
		}

		#endregion

		#region - Private methods -

#if (SILVERLIGHT)

		private static T[] GetValues<T>()
		{
			Type enumType = typeof(T);

			if (!enumType.IsEnum)
			{
				throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
			}

			List<T> values = new List<T>();

			var fields = from field in enumType.GetFields()
						 where field.IsLiteral
						 select field;

			foreach (FieldInfo field in fields)
			{
				object value = field.GetValue(enumType);
				values.Add((T)value);
			}

			return values.ToArray();
		}

		private static object[] GetValues(Type enumType)
		{
			if (!enumType.IsEnum)
			{
				throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
			}

			List<object> values = new List<object>();

			var fields = from field in enumType.GetFields()
						 where field.IsLiteral
						 select field;

			foreach (FieldInfo field in fields)
			{
				object value = field.GetValue(enumType);
				values.Add(value);
			}

			return values.ToArray();
		}

#endif

		#endregion
	}

	#endregion
}
